# Joao Lencart e Silva: j.lencart@ua.pt
from odcutils._etc._parts import *
import netCDF4
from netCDF4 import Dataset
import csv
import numpy as np
from datetime import datetime

# Set default encoding
netCDF4.default_encoding = 'utf-8'

def nc2odv(fin, fout = None, cruise = None, cast = 'both'):
    """Converts a netcdf file into an ascii odv spreadsheet.
       Currently works for single cast CTD files.
            fin : input netcdf filename
            fout: output odv txt filename
            cruise: name of the campaign
            cast: 'both', 'down', 'up'
    """
    print fin
    # Create output file name
    if fout == None:
        fout = '.'.join(fin.split('.')[:-1]) + '.txt'
    # Create cruise name
    if cruise == None:
        cruise = 'Demo Cruise'
    # Open NetCDF file
    nc = Dataset(fin)
    # Get dimensions
    t_dim = nc.dimensions['time']
    z_dim = nc.dimensions['z']
    lon_dim = nc.dimensions['lon']
    lat_dim = nc.dimensions['lat']
    nvars = len(nc.variables.keys())
    z = nc.variables['z'][:]
    zmaxi = np.argmax(z)
    fscans = max([len(t_dim), len(z_dim), len(lon_dim), len(lat_dim)])
    # Select cast
    if cast.lower() == 'down':
        scan_i = range(0, zmaxi + 1)
        nscans = len(scan_i)
    elif cast.lower() == 'up':
        scan_i = range(zmaxi, fscans)
        nscans = len(scan_i)
    elif cast.lower() == 'both':
        nscans = fscans
        scan_i = range(0, nscans)
    else:
        raise WrongInput(cast)

    # Get variable names
    vnames = nc.variables.keys()
    # Get station name
    station = nc.station_id
    # Get type
    pcode = nc.package_code
    # Determine max depth
    try:
        fv = nc._FillValue
        if nc.water_depth != fv:
            bottom = nc.water_depth
        else:
            bottom = max(nc.variables['z'][:])
    except:
        if nc.water_depth != []:
            bottom = nc.water_depth
        else:
            bottom = max(nc.variables['z'][:])
    # Initialise arrays
    shortn = []
    stdn = []
    varout = []
    oddd = [[cruise], [station], [pcode], [bottom]]
    # Initialise datime object
    # Loop variable
    for var in nc.variables.keys():
    # Skip variables not equal to nscans
        if len(nc.variables[var][scan_i]) != nscans:
            if var == 'time':
                tdo = dTime2Loch(nc.variables['time'][scan_i] / 3600 / 24,\
                out = 'do')
                time = tdo.strftime('%Y-%m-%d %H:%M:%S')
                oddd.append(list([time]))
            else:
                oddd.append(list(nc.variables[var][scan_i]))
        else:
    # Get variable short_names and standard names
            shortn.append(nc.variables[var].short_name)
            stdn.append(nc.variables[var].standard_name)
            if var == 'time':
                tdo = map(dTime2Loch, nc.variables['time'][scan_i]\
                                      / 3600 / 24, ['do'] * nscans)
                time = map(datetime.strftime, tdo, \
                                              ['%Y-%m-%d %H:%M:%S'] * nscans)
                varout.append(list([time]))
            else:
                varout.append(list(nc.variables[var][scan_i]))
    # Close NetCDF file
    nc.close()
    # Build dictionary for convinience
    vard = dict(zip(shortn, varout))
    # Convert to np array
#    try:
#    print varout
    varout = np.array(varout)
#    except:
#        print varout
    # Transpose
    varout = varout.transpose()
    # Convert to lists of rows
    varout = map(list, varout)
    # Create header
    lheader = ['Cruise', 'Station', 'Type', ['Bottom']]
    lheader.extend(vnames)
    vout = []
    # Create metadata
    for line in varout:
        lodd = []
        for k in oddd:
            lodd.extend(k)
        lodd.extend(line)
        vout.append(lodd)
    out = []
    # Append header to data
    out = [lheader]
    out.extend(vout)
    # Open csv file
    f1 = open(fout, 'w')
    # Create dialect object as excell
    dialect = csv.excel
    # Change delimiter to tab
    dialect.delimiter = '\t'
    # Create csv file writter object
    writer = csv.writer(f1, dialect)
    # Write to csv file
    writer.writerows(out)
    # Close csv file
    f1.close()

class WrongInput(Exception):
   def __init__(self, value):
       self.value = value
   def __str__(self):
       return (self.value)
